package com.atguigu.gmall.search.service.impl;

import com.atguigu.gmall.search.Goods;
import com.atguigu.gmall.search.repo.GoodsRepository;
import com.atguigu.gmall.search.service.SearchService;
import com.atguigu.gmall.search.vo.SearchParamVo;
import com.atguigu.gmall.search.vo.SearchRespVo;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.HighlightQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;


import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;


@Service
public class SearchServiceImpl implements SearchService {
    @Autowired
    GoodsRepository goodsRepository;
    @Autowired
    ElasticsearchRestTemplate restTemplate;
    int pageSize = 10;

    @Override
    public SearchRespVo search(SearchParamVo searchParamVo) {
        //根据前端请求参数 来封装Query
        Query query = buildQuery(searchParamVo);
        //TODO 得到检索的结果
        SearchHits<Goods> result = restTemplate.search(query, Goods.class, IndexCoordinates.of("goods"));

        //todo 根据返回值结果 返回前端所需要的结果
        SearchRespVo respVo = buildSearchResp(result, searchParamVo);

        return respVo;
    }

    private SearchRespVo buildSearchResp(SearchHits<Goods> result, SearchParamVo searchParamVo) {
        SearchRespVo searchRespVo = new SearchRespVo();
        //todo 1 检索参数   private  SearchParamVo searchParamVo
        searchRespVo.setSearchParamVo(searchParamVo);

        //TODO 2 品牌面包屑    private List<Props> propsParamList;
        if (!StringUtils.isEmpty(searchParamVo.getTrademark())) {
            searchRespVo.setTrademarkParam("品牌参数" + searchParamVo.getTrademark().split(":")[1]);
        }

        // todo 3 属性面包屑
        if (searchParamVo.getProps() != null && searchParamVo.getProps().length > 0) {
            //遍历前端所传的参数
            List<SearchRespVo.Props> collect = Arrays.stream(searchParamVo.getProps()).map(
                    item -> {
                        String[] split = item.split(":");
                        SearchRespVo.Props props = new SearchRespVo.Props();
                        props.setAttrName(split[2]);
                        props.setAttrValue(split[1]);
                        props.setAttrId(Long.parseLong(split[0]));
                        return props;
                    }).collect(Collectors.toList());
            searchRespVo.setPropsParamList(collect);
        }

           // TODO 品牌列表 聚合      private  List<Trademark> trademarkList;
        ParsedLongTerms tmIdAgg = result.getAggregations().get("tmIdAgg");

        List<SearchRespVo.Trademark> trademarks = tmIdAgg.getBuckets().stream().map(bucket -> {
            SearchRespVo.Trademark trademark = new SearchRespVo.Trademark();
            //品牌id
            long tmId = bucket.getKeyAsNumber().longValue();
            trademark.setTmId(tmId);
            //品牌名字
            ParsedStringTerms tmNameAgg = bucket.getAggregations().get("tmNameAgg");
            String tmName = tmNameAgg.getBuckets().get(0).getKeyAsString();
            trademark.setTmName(tmName);

            //品牌 logo
            ParsedStringTerms tmLogoAgg = bucket.getAggregations().get("tmLogoAgg");
            String tmLogo = tmLogoAgg.getBuckets().get(0).getKeyAsString();
            trademark.setTmLogoUrl(tmLogo);
            return trademark;
        }).collect(Collectors.toList());
        searchRespVo.setTrademarkList(trademarks);


        // TODO 属性列表     private  List<Attrs> attrsList;
        ParsedNested attrAgg = result.getAggregations().get("attrAgg");
        ParsedLongTerms attrIdAgg = attrAgg.getAggregations().get("attrIdAgg");
        //java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
        List<SearchRespVo.Attrs> attrsList = attrIdAgg.getBuckets().stream().map(
                bucket -> {
                    SearchRespVo.Attrs attrs = new SearchRespVo.Attrs();
                    //属性id
                    long attrId = bucket.getKeyAsNumber().longValue();
                    attrs.setAttrId(attrId);
                    //属性名
                    ParsedStringTerms attrNameAgg = bucket.getAggregations().get("attrNameAgg");
                    //TODO 少一步判断
                    if (attrNameAgg.getBuckets().size() > 0) {
                        String attrName = attrNameAgg.getBuckets().get(0).getKeyAsString();
                        attrs.setAttrName(attrName);
                    }


                    //属性值
                    ParsedStringTerms attrValueAgg = bucket.getAggregations().get("attrValueAgg");
                    List<String> valueList = attrValueAgg.getBuckets().stream().map(
                            item -> item.getKeyAsString()).collect(Collectors.toList());
                    attrs.setAttrValueList(valueList);
                    return attrs;
                }
        ).collect(Collectors.toList());
        searchRespVo.setAttrsList(attrsList);
      //   TODO  private  String urlParam;
          String urlParam= buildUrlParam(searchParamVo);
          searchRespVo.setUrlParam(urlParam);
          //TODO 5  private  OrderMap  orderMap;
        if(!StringUtils.isEmpty(searchParamVo.getOrder())){
            SearchRespVo.OrderMap   orderMap =new SearchRespVo.OrderMap();
            String[] split = searchParamVo.getOrder().split(":");
            orderMap.setSort(split[1]);
            orderMap.setType(split[0]);
            searchRespVo.setOrderMap(orderMap);
        }
        //TODO 商品集合    private  List<Object> goodsList;
        List<Goods> goods = result.getSearchHits().stream()
                .map(item -> {
                    Goods content = item.getContent();
                    if(!StringUtils.isEmpty(searchParamVo.getKeyword())){
                        //模糊检索带高亮显示
                        String newTitle = item.getHighlightField("title").get(0);
                        content.setTitle(newTitle);
                    }
                    return content;
                })
                .collect(Collectors.toList());
           searchRespVo.setGoodsList(goods);

           //  TODO 页码      private  Long  pageNo
        searchRespVo.setPageNo(searchParamVo.getPageNo());
        //总记录
        //总页码： 总记录数%每页大小==0？总记录数/每页大小:总记录数/每页大小 + 1
        long totalHits = result.getTotalHits();
        searchRespVo.setTotalPages(totalHits%pageSize==0?totalHits/pageSize:totalHits/pageSize+1);

        return  searchRespVo;
    }

    private String buildUrlParam(SearchParamVo searchParamVo) {
        StringBuilder  builder =new StringBuilder("list.html?");
        //分类参数
        if (searchParamVo.getCategory1Id()!=null) {
            builder.append("&category1Id="+searchParamVo.getCategory1Id());
        }
        if (searchParamVo.getCategory2Id()!=null) {
            builder.append("&category2Id="+searchParamVo.getCategory2Id());
        }
        if (searchParamVo.getCategory3Id()!=null) {
            builder.append("&category3Id="+searchParamVo.getCategory3Id());
        }

        //keyword
        if (!StringUtils.isEmpty(searchParamVo.getKeyword())) {
            builder.append("&keyword="+searchParamVo.getKeyword());
        }

        //品牌
        if(!StringUtils.isEmpty(searchParamVo.getTrademark())){
            builder.append("&trademark="+searchParamVo.getTrademark());
        }

        //属性
        if(searchParamVo.getProps()!=null && searchParamVo.getProps().length>0){
            Arrays.stream(searchParamVo.getProps()).forEach(item->{
                builder.append("&props="+item);
            });
        }
        return  builder.toString();
    }


    /**
     * 开始查询条件
     *
     * @param searchParamVo
     * @return
     */
    private Query buildQuery(SearchParamVo searchParamVo) {
//        //1、查询条件
//        BoolQueryBuilder bool = QueryBuilders.boolQuery();
//        //构建bool里面的查询条件
//        //1.1）、一级分类
//        if (searchParamVo.getCategory1Id()!=null) {
//            TermQueryBuilder term = QueryBuilders.termQuery("category1Id", searchParamVo.getCategory1Id());
//            bool.must(term);
//        }
//        //1.2）、二级分类
//        if (searchParamVo.getCategory2Id() != null) {
//            TermQueryBuilder term = QueryBuilders.termQuery("category2Id", searchParamVo.getCategory2Id());
//            bool.must(term);
//        }
//        //1.3）、三级分类
//        if (searchParamVo.getCategory3Id() != null) {
//            TermQueryBuilder term = QueryBuilders.termQuery("category3Id", searchParamVo.getCategory3Id());
//            bool.must(term);
//        }
//        //1.4）、关键字查询
//        if (!StringUtils.isEmpty(searchParamVo.getKeyword())) {
//            MatchQueryBuilder match = QueryBuilders.matchQuery("title", searchParamVo.getKeyword());
//            bool.must(match);
//        }
//        //1.5）、品牌查询
//        if (!StringUtils.isEmpty(searchParamVo.getTrademark())) {
//            String[] split = searchParamVo.getTrademark().split(":");
//            TermQueryBuilder term = QueryBuilders.termQuery("tmId", split[0]);
//            bool.must(term);
//        }
//        //1.6）、属性查询
//        if (searchParamVo.getProps()!=null && searchParamVo.getProps().length>0) {
//            Arrays.stream(searchParamVo.getProps())
//                    .forEach(item->{
//                        //4:256GB:机身存储
//                        String[] split = item.split(":");
//                        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
//                        //属性id条件
//                        boolQuery.must(QueryBuilders.termQuery("attrs.attrId",split[0]));
//                        //属性值条件
//                        boolQuery.must(QueryBuilders.termQuery("attrs.attrValue",split[1]));
//
//                        NestedQueryBuilder nested = QueryBuilders.nestedQuery("attrs",boolQuery, ScoreMode.None);
//                        bool.must(nested);
//                    });
//        }
//
//        //=============查询结束==============
//        //创建一个原生Query
//        NativeSearchQuery query = new NativeSearchQuery(bool);
//
//        //=============排序开始==============
//        if (!StringUtils.isEmpty(searchParamVo.getOrder())) {
//            //1/2:asc/desc    1:asc
//            String[] split = searchParamVo.getOrder().split(":");
//            Sort.Direction direction = "asc".equals(split[1])?Sort.Direction.ASC:Sort.Direction.DESC;
//            Sort sort = null;
//            switch (split[0]){
//                case "1":
//                    sort = Sort.by(direction, "hotScore");
//                    break;
//                case "2":
//                    sort = Sort.by(direction, "price");
//                    break;
//                default:
//                    sort = Sort.by(Sort.Direction.DESC, "hotScore");
//            }
//            query.addSort(sort);
//        }
//        //=============排序结束==============
//
//
//        //=============分页开始==============
//        //页码是从0开始
//        //Pageable pageable = PageRequest.of(searchParamVo.getPageNo()-1,pageSize);
//        PageRequest pageable = PageRequest.of(searchParamVo.getPageNo() - 1, pageSize);
//        query.setPageable(pageable);
//        //=============分页结束==============
//
//
//        //==============高亮===============
//        if(!StringUtils.isEmpty(searchParamVo.getKeyword())){
//            //1、构建高亮
//            HighlightBuilder builder = new HighlightBuilder()
//                    .field("title")
//                    .preTags("<span style='color:red'>")
//                    .postTags("</span>");
//
//            HighlightQuery highlightQuery = new HighlightQuery(builder);
//            query.setHighlightQuery(highlightQuery);
//        }
//
//
//        //=============聚合分析开始==品牌============
//        //品牌id聚合
//        TermsAggregationBuilder tmIdAgg = AggregationBuilders
//                .terms("tmIdAgg")
//                .field("tmId")
//                .size(200);
//
//        //品牌name子聚合
//        TermsAggregationBuilder tmNameAgg = AggregationBuilders
//                .terms("tmNameAgg")
//                .field("tmName")
//                .size(1);
//        tmIdAgg.subAggregation(tmNameAgg);
//        //品牌logo子聚合
//        TermsAggregationBuilder tmLogoAgg = AggregationBuilders
//                .terms("tmLogoAgg")
//                .field("tmLogoUrl")
//                .size(1);
//        tmIdAgg.subAggregation(tmLogoAgg);
//
//        query.addAggregation(tmIdAgg);
//
//
//        //=============聚合分析开始==属性============
//        NestedAggregationBuilder attrAgg = AggregationBuilders.nested("attrAgg", "attrs");
//
//        //属性id聚合分析
//        TermsAggregationBuilder attrIdAgg = AggregationBuilders
//                .terms("attrIdAgg")
//                .field("attrs.attrId")
//                .size(200);
//        //属性名聚合分析
//        TermsAggregationBuilder attrNameAgg = AggregationBuilders
//                .terms("attrNameAgg")
//                .field("attrs.attrName")
//                .size(1);
//        attrIdAgg.subAggregation(attrNameAgg);
//
//        //属性值聚合分析
//        TermsAggregationBuilder attrValueAgg = AggregationBuilders
//                .terms("attrValueAgg")
//                .field("attrs.attrValue")
//                .size(100);
//        attrIdAgg.subAggregation(attrValueAgg);
//
//        attrAgg.subAggregation(attrIdAgg);
//        query.addAggregation(attrAgg);
//        //=============聚合分析结束==============
//
//
//
//        return query;
        //=============查询开始==============
        //1、查询条件
        BoolQueryBuilder bool = QueryBuilders.boolQuery();
        //构建bool里面的查询条件
        //1.1）、一级分类
        if (searchParamVo.getCategory1Id()!=null) {
            TermQueryBuilder term = QueryBuilders.termQuery("category1Id", searchParamVo.getCategory1Id());
            bool.must(term);
        }
        //1.2）、二级分类
        if (searchParamVo.getCategory2Id() != null) {
            TermQueryBuilder term = QueryBuilders.termQuery("category2Id", searchParamVo.getCategory2Id());
            bool.must(term);
        }
        //1.3）、三级分类
        if (searchParamVo.getCategory3Id() != null) {
            TermQueryBuilder term = QueryBuilders.termQuery("category3Id", searchParamVo.getCategory3Id());
            bool.must(term);
        }
        //1.4）、关键字查询
        if (!StringUtils.isEmpty(searchParamVo.getKeyword())) {
            MatchQueryBuilder match = QueryBuilders.matchQuery("title", searchParamVo.getKeyword());
            bool.must(match);
        }
        //1.5）、品牌查询
        if (!StringUtils.isEmpty(searchParamVo.getTrademark())) {
            String[] split = searchParamVo.getTrademark().split(":");
            TermQueryBuilder term = QueryBuilders.termQuery("tmId", split[0]);
            bool.must(term);
        }
        //1.6）、属性查询
        if (searchParamVo.getProps()!=null && searchParamVo.getProps().length>0) {
            Arrays.stream(searchParamVo.getProps())
                    .forEach(item->{
                        //4:256GB:机身存储
                        String[] split = item.split(":");
                        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
                        //属性id条件
                        boolQuery.must(QueryBuilders.termQuery("attrs.attrId",split[0]));
                        //属性值条件
                        boolQuery.must(QueryBuilders.termQuery("attrs.attrValue",split[1]));

                        NestedQueryBuilder nested = QueryBuilders.nestedQuery("attrs",boolQuery, ScoreMode.None);
                        bool.must(nested);
                    });
        }

        //=============查询结束==============
        //创建一个原生Query
        NativeSearchQuery query = new NativeSearchQuery(bool);

        //=============排序开始==============
        if (!StringUtils.isEmpty(searchParamVo.getOrder())) {
            //1/2:asc/desc    1:asc
            String[] split = searchParamVo.getOrder().split(":");
            Sort.Direction direction = "asc".equals(split[1])?Sort.Direction.ASC:Sort.Direction.DESC;
            Sort sort = null;
            switch (split[0]){
                case "1":
                    sort = Sort.by(direction, "hotScore");
                    break;
                case "2":
                    sort = Sort.by(direction, "price");
                    break;
                default:
                    sort = Sort.by(Sort.Direction.DESC, "hotScore");
            }
            query.addSort(sort);
        }
        //=============排序结束==============


        //=============分页开始==============
        //页码是从0开始
        Pageable pageable = PageRequest.of(searchParamVo.getPageNo()-1,pageSize);
        query.setPageable(pageable);
        //=============分页结束==============


        //==============高亮===============
        if(!StringUtils.isEmpty(searchParamVo.getKeyword())){
            //1、构建高亮
            HighlightBuilder builder = new HighlightBuilder()
                    .field("title")
                    .preTags("<span style='color:red'>")
                    .postTags("</span>");

            HighlightQuery highlightQuery = new HighlightQuery(builder);
            query.setHighlightQuery(highlightQuery);
        }


        //=============聚合分析开始==品牌============
        //品牌id聚合
        TermsAggregationBuilder tmIdAgg = AggregationBuilders
                .terms("tmIdAgg")
                .field("tmId")
                .size(200);

        //品牌name子聚合
        TermsAggregationBuilder tmNameAgg = AggregationBuilders
                .terms("tmNameAgg")
                .field("tmName")
                .size(1);
        tmIdAgg.subAggregation(tmNameAgg);
        //品牌logo子聚合
        TermsAggregationBuilder tmLogoAgg = AggregationBuilders
                .terms("tmLogoAgg")
                .field("tmLogoUrl")
                .size(1);
        tmIdAgg.subAggregation(tmLogoAgg);

        query.addAggregation(tmIdAgg);


        //=============聚合分析开始==属性============
        NestedAggregationBuilder attrAgg = AggregationBuilders.nested("attrAgg", "attrs");

        //属性id聚合分析
        TermsAggregationBuilder attrIdAgg = AggregationBuilders
                .terms("attrIdAgg")
                .field("attrs.attrId")
                .size(200);
        //属性名聚合分析
        TermsAggregationBuilder attrNameAgg = AggregationBuilders
                .terms("attrNameAgg")
                .field("attrs.attrName")
                .size(1);
        attrIdAgg.subAggregation(attrNameAgg);

        //属性值聚合分析
        TermsAggregationBuilder attrValueAgg = AggregationBuilders
                .terms("attrValueAgg")
                .field("attrs.attrValue")
                .size(100);
        attrIdAgg.subAggregation(attrValueAgg);

        attrAgg.subAggregation(attrIdAgg);
        query.addAggregation(attrAgg);
        //=============聚合分析结束==============



        return query;
     }

    @Override
    public void save(Goods goods) {
        goodsRepository.save(goods);
    }

    @Override
    public void down(Long skuId) {
        goodsRepository.deleteById(skuId);
    }
}
